<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>testArea</title>
    <script type="text/javascript" src="../doc/asset/js/esl/esl.js"></script>
</head>
<body>
    <script type="text/javascript">
        var zr;
        var shape;
        var isInside;
        var isOutside;
        var _util;
        var _ctx;
        var _shape;
        var index = 0;

        require.config({
            paths: {
                'js': '../doc/asset/js/esl/js'
            }
        });

        require(["../src/zrender",
            "../src/tool/area",
            '../src/tool/util',
            '../src/shape'], function(zrender, area, util, shape){

            // 初始化zrender
            zr = zrender.init( document.getElementById("Main") );
            render();

            isInside = area.isInside;
            isOutside = area.isOutside;

            _util = util;
            _shape = shape;
        })

        // 渲染canvas
        function render() {
            zr.clear();
            shape = randomShape();
            zr.addShape( shape );
            console.log()
            zr.render();
        }

        // 测试耗时
        function test() {
            var n = 600;
            var m = 400;
            if (!_ctx) {
                _ctx = _util.getContext();
            }
            // 计算纯数学方法耗时
            var time = new Date().getTime();
            for (var i = 0; i < n ; i ++ ) {
                for (var j = 0; j < m ; j ++ ) {
                    testSwitch(shape.shape, shape.style, i , j)
                }
            }
            $('switch').innerHTML = new Date().getTime() - time;

            // 计算buildPath方法耗时
            time = new Date().getTime();

            for (var i = 0; i < n ; i ++ ) {
                for (var j = 0; j < m ; j ++ ) {
                    testBuildPath(shape.shape, shape.style, i , j)
                }
            }
            $('build').innerHTML = new Date().getTime() - time;

            // 计算获取像素方法耗时
            time = new Date().getTime();

            for (var i = 0; i < n ; i ++ ) {
                for (var j = 0; j < m ; j ++ ) {
                    testPixel(shape.shape, shape.style, i , j)
                }
            }
            $('pixel').innerHTML = new Date().getTime() - time;
        }

        function $(id) {
            return document.getElementById(id);
        }

        // 生成shape
        function randomShape() {
            index ++;
            return {
                shape : ['line', 'beziercurve', 'brokenLine', 'ring', 'rectangle', 'sector', 'polygon', 'circle'][index % 8],
                position : [random(600), random(400)],
                scale : [1, 1],
                style : {
                    x : 50,
                    y : 50,
                    a : 50,
                    b: 50,
                    r : random(200),
                    xStart : random(600),
                    yStart : random(400),
                    cpX1 : 100,
                    cpY1 : 100,
                    startAngle : 0,
                    endAngle: random(360),
                    xEnd : random(600),
                    yEnd : random(400),
                    width : random(600),
                    height : random(400),
                    pointList : [[10, 10], [300, 20], [298, 400], [50, 450]],
                    color : 'rgba(220, 20, 60, 0.8)',
                    strokeColor : "rgba(220, 20, 60, 0.8)",
                    lineWidth : 5,
                    brushType : 'stroke',
                    text :'test',
                    textPosition :'inside'
                },
                draggable: true
            }
        }

        // 随机一个整数
        function random(max) {
            return Math.min(Math.floor(Math.random() * (max + 1)), max);
        }

        // 测试buildPath
        function testBuildPath(zoneType, area, x, y) {


            var sectorClazz = _shape.get(zoneType);
            // 图形类实现路径创建了则用类的path
            _ctx.beginPath();
            sectorClazz.buildPath(_ctx, area);
            _ctx.closePath();
            return _ctx.isPointInPath(x, y);
        }

        // 测试获取像素方法
        function testPixel(zoneType, area, x, y) {
            var sectorClazz = _shape.get(zoneType);

            _ctx.clearRect(0, 0, 600, 400);
            _ctx.beginPath();
            sectorClazz.brush(_ctx, shape);
            _ctx.closePath();

            isPainted(_ctx, x, y);
        }

        // 判断坐标是否已经被画过
        function isPainted(context, x, y, unit) {
            var unit = unit || 1;
            var pixels;

            if (unit) {
                pixels = context.getImageData(x - Math.floor(unit / 2), y - Math.floor(unit / 2), unit, unit);
            }
            else {
                pixels = context.getImageData(x, y, 1, 1);
            }

            var data = pixels.data;
            var len = data.length;

            for (var i = 0 ; i < len ; i++) {
                if (data[i] != 0) {
                    return true;
                }
            }
            return false;
        }

        /**
         * 测试纯数学计算
         */
        function testSwitch(zoneType, area, x, y) {
            switch (zoneType) {
                //线-----------------------1
                case 'line':
                    return _isInsideLine(area, x, y);
                //折线----------------------2
                case 'brokenLine':
                    return _isInsideBrokenLine(area, x, y);
                //文本----------------------3
                case 'text':
                    return true;
                //圆环----------------------4
                case 'ring':
                    return _isInsideRing(area, x, y);
                //矩形----------------------5
                case 'rectangle':
                    return true;
                //圆形----------------------6
                case 'circle':
                    return _isInsideCircle(area, x, y);
                //扇形----------------------7
                case 'sector':
                    return _isInsideSector(area, x, y);
                //多边形---------------------8
                case 'polygon':
                    return _isInsidePolygon(area, x, y);
                //图片----------------------9
                case 'image':
                    return true;
                //心形----------------------10
                case 'heart':
                    return true;    // Todo，不精确
                //水滴----------------------11
                case 'droplet':
                    return true;    // Todo，不精确
                //椭圆----------------------12
                case 'ellipse':
                    return false;    // Todo，不精确
                //路径----------------------13
                case 'path':
                    return false;   // Todo，暂不支持
            }
        }

        /**
         * 线段包含判断
         */
        function _isInsideLine(area, x, y) {
            //水平、垂直快捷判断
            if (area.xStart == area.xEnd) {
                //垂直线判断
                return area.yStart <= y
                       && area.yEnd >= y
                       && Math.abs(area.xStart - x) < (area.lineWidth || 1);
            }
            if (area.yStart == area.yEnd){
                //水平线判断
                return area.xStart <= x
                       && area.xEnd >= x
                       && Math.abs(area.yStart - y) < (area.lineWidth || 1);
            }

            //斜线判断
            return Math.abs(
                       Math.abs(
                           (area.xStart - x)
                           * (area.yStart - area.yEnd)
                           / (area.xStart - area.xEnd)
                           - area.yStart
                       )
                       - y
                  )
                  < (area.lineWidth || 1);
        }

        function _isInsideBrokenLine(area, x, y) {
            var pointList = area.pointList;
            var lineArea;
            var insideCatch = false;
            for (var i = 0, l = pointList.length - 1; i < l; i++) {
                lineArea = {
                    xStart : pointList[i][0],
                    yStart : pointList[i][1],
                    xEnd : pointList[i + 1][0],
                    yEnd : pointList[i + 1][1],
                    lineWidth : area.lineWidth
                };
                insideCatch = isInside('line', lineArea, x, y);
                if (insideCatch) {
                    break;
                }
            }
            return insideCatch;
        }

        function _isInsideRing(area, x, y) {
            if (isInside('circle', area, x, y)
                && isOutside(
                    'circle',
                    {
                        x : area.x,
                        y : area.y,
                        r : area.r0 || 0
                    },
                    x, y
                )
            ){
                // 大圆内，小圆外
                return true;
            }
            return false;
        }

        /**
         * 矩形包含判断
         */
        function _isInsideRectangle(area, x, y) {
            if (x >= area.x
                && x <= (area.x + area.width)
                && y >= area.y
                && y <= (area.y + area.height)
            ) {
                return true;
            }
            return false;
        }

        /**
         * 圆形包含判断
         */
        function _isInsideCircle(area, x, y) {
            return (x - area.x) * (x - area.x) + (y - area.y) * (y - area.y)
                   < area.r * area.r;
        }

        /**
         * 扇形包含判断
         */
        function _isInsideSector(area, x, y) {
            if (isOutside('circle', area, x, y)
                || (area.r0 > 0
                    && isInside(
                            'circle',
                            {
                                x : area.x,
                                y : area.y,
                                r : area.r0
                            },
                            x, y
                        )
                    )
            ){
                // 大圆外或者小圆内直接false
                return false;
            }
            else {
                // 判断夹角
                var angle = (360
                             - Math.atan2(y - area.y, x - area.x)
                             / Math.PI
                             * 180)
                             % 360;
                return (angle >= area.startAngle && angle <= area.endAngle);
            }
        }

        /**
         * 多边形包含判断
         * 警告：下面这段代码会很难看，建议跳过~
         */
        function _isInsidePolygon(area, x, y) {
            /**
             * 射线判别法
             * 如果一个点在多边形内部，任意角度做射线肯定会与多边形要么有一个交点，要么有与多边形边界线重叠
             * 如果一个点在多边形外部，任意角度做射线要么与多边形有一个交点，
             * 要么有两个交点，要么没有交点，要么有与多边形边界线重叠。
             */
            var i;
            var j;
            var polygon = area.pointList;
            var N = polygon.length;
            var inside = false;
            var redo = true;
            var v;
            var left = 0;
            var right = 0;

            for (i = 0; i < N; ++i) {
                // 是否在顶点上
                if (polygon[i][0] == x && polygon[i][1] == y ) {
                    redo = false;
                    inside = true;
                    break;
                }
            }

            if (redo) {
                redo = false;
                inside = false;
                for (i = 0,j = N - 1;i < N;j = i++) {
                    if ((polygon[i][1] < y && y < polygon[j][1])
                        || (polygon[j][1] < y && y < polygon[i][1])
                    ) {
                        if (x <= polygon[i][0] || x <= polygon[j][0]) {
                            v = (y - polygon[i][1])
                                * (polygon[j][0] - polygon[i][0])
                                / (polygon[j][1] - polygon[i][1])
                                + polygon[i][0];
                            if (x < v) {          // 在线的左侧
                                inside = !inside;
                            }
                            else if (x == v) {   // 在线上
                                inside = true;
                                break;
                            }
                        }
                    }
                    else if (y == polygon[i][1]) {
                        if (x < polygon[i][0]) {    // 交点在顶点上
                            polygon[i][1] > polygon[j][1] ? --y : ++y;
                            //redo = true;
                            break;
                        }
                    }
                    else if (polygon[i][1] == polygon[j][1] // 在水平的边界线上
                             && y == polygon[i][1]
                             && ((polygon[i][0] < x && x < polygon[j][0])
                                 || (polygon[j][0] < x && x < polygon[i][0]))
                    ) {
                        inside = true;
                        break;
                    }
                }
            }
            return inside;
        }
    </script>
    <div id="Main" style="width:600px;height:400px;"></div>
    <input type="button" value="生成图形" onclick="render()"/>
    <input type="button" value="test" onclick="test()"/>
    <h3>从(1,1)到(600,400)执行下面的方法</h3>
    <p >switch的那一坨耗时 <span id="switch"></span> ms</p>
    <p >buildPath耗时 <span id="build"></span> ms</p>
    <p >像素判断耗时 <span id="pixel"></span> ms</p>
</body>
</html>